//
//  Init.swift
//  cnswift-demo
//
//  Created by YangWei on 2021/1/1.
//  Copyright © 2021 YangWei. All rights reserved.
//

import UIKit

class Initialization: SWDBaseObject {
    
    class func run() {
        
        let initialization = Initialization()
        
        // 1.1
        initialization.initializers()
        
        // 1.2
        initialization.defaultPropertyValues()
        
        // 2.1
        initialization.initializationParameters()
        
        // 2.2
        initialization.parameterNamesAndArgumentLabels()
        
        // 2.3
        initialization.initializerParametersWithoutArgumentLabels()
        
        // 2.4
        initialization.optionalPropertyTypes()
        
        // 2.5
        initialization.assigningConstantPropertiesDuringInitialization()
        
        // 3
        initialization.defaultInitializers()
        
        // 3.1
        initialization.memberwiseInitializersForStructureTypes()
        
        // 4
        initialization.initializerDelegationForValueTypes()
        
        // 5.5
        initialization.initializerInheritanceAndOverriding()
        
        // 5.7
        initialization.designatedAndConvenienceInitializersInAction()
        
        // 6
        initialization.failableInitializers()
        
        // 6.1
        initialization.failableInitializersForEnumerations()
        
        // 6.2
        initialization.failableInitializersForEnumerationsWithRawValues()
        
        // 6.3
        initialization.propagationOfInitializationFailure()
        
        // 6.4
        initialization.overridingAFailableInitializer()
        
        // 7
        initialization.requiredInitializers()
        
        // 8
        initialization.settingADefaultPropertyValueWithAClosureOrFunction()
    }
    
    /// 1.1 构造器
    func initializers() {
        let title = "1.1 构造器";
        printStartLine(title)
        
        let f = Fahrenheit()
        print("The default temperature is \(f.temperature)° Fahrenheit")
        // 打印“The default temperature is 32.0° Fahrenheit”
        
        printEndLine(title)
    }
    
    /// 1.2 默认属性值
    func defaultPropertyValues() {
        let title = "1.2 默认属性值";
        printStartLine(title)
        
        let f = FahrenheitV2()
        print("The default temperature is \(f.temperature)° Fahrenheit")
        // 打印“The default temperature is 32.0° Fahrenheit”
        
        printEndLine(title)
    }
    
    /// 2.1 形参的构造过程
    func initializationParameters() {
        let title = "2.1 形参的构造过程";
        printStartLine(title)
        
        let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
        // boilingPointOfWater.temperatureInCelsius 是 100.0
        print(boilingPointOfWater)
        
        let freezingPointOfWater = Celsius(fromKelvin: 273.15)
        // freezingPointOfWater.temperatureInCelsius 是 0.0
        print(freezingPointOfWater)
        
        printEndLine(title)
    }
    
    /// 2.2 形式命名和实参标签
    func parameterNamesAndArgumentLabels() {
        let title = "2.2 形式命名和实参标签";
        printStartLine(title)
        
        // 使用两种构造器分别创建一个新的 Color 实例
        let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
        print(magenta)
        let halfGray = Color(white: 0.5)
        print(halfGray)

//        let veryGreen = Color(0.0, 1.0, 0.0)
        // 报编译期错误-需要实参标签
        
        printEndLine(title)
    }
    
    /// 2.3 不带实参标签的构造器形参
    func initializerParametersWithoutArgumentLabels() {
        let title = "2.3 不带实参标签的构造器形参";
        printStartLine(title)
        
        // 当参数意图足够清晰表达用途时，可以不显示实参标签
        // 使用构造器 init(_ celsius: Double) 调用时不需要显示实参标签
        let bodyTemperature = Celsius(37.0)
        // bodyTemperature.temperatureInCelsius is 37.0
        print(bodyTemperature)
        
        printEndLine(title)
    }
    
    /// 2.4 可选属性类型
    func optionalPropertyTypes() {
        let title = "2.4 可选属性类型";
        printStartLine(title)
        
        let cheeseQuestion = SurveyQuestion(text: "Do you like cheese?")
        cheeseQuestion.ask()
        // 打印“Do you like cheese?”
        cheeseQuestion.response = "Yes, I do like cheese."
        
        printEndLine(title)
    }
    
    /// 2.5 构造过程中常量属性的赋值
    func assigningConstantPropertiesDuringInitialization() {
        let title = "2.5 构造过程中常量属性的赋值";
        printStartLine(title)
        
        // 构造 SurveyQuestionV2 实例后，text 属性值不可以被修改
        let beetsQuestion = SurveyQuestionV2(text: "How about beets?")
        beetsQuestion.ask()
        // 打印“How about beets?”
        beetsQuestion.response = "I also like beets. (But not with cheese.)"
        
        printEndLine(title)
    }
    
    /// 3 默认构造器
    func defaultInitializers() {
        let title = "3 默认构造器";
        printStartLine(title)
        
        // 使用默认构造器创造了一个 ShoppingListItem 类的实例
        let item = ShoppingListItem()
        print(item.name as Any, item.quantity, item.purchased)
        
        printEndLine(title)
    }
    
    /// 3.1 结构体的逐一成员构造器
    func memberwiseInitializersForStructureTypes() {
        let title = "3.1 结构体的逐一成员构造器";
        printStartLine(title)
        
        // 用自动获得的构造器创建新的 Size 实例
        let twoByTwo = SizeV2(width: 2.0, height: 2.0)
        print(twoByTwo.width, twoByTwo.height)
        
        /*
        Size 结构体的 height 和 width 属性各有一个默认值。
        可以省略两者或两者之一，被省略的属性，
        构造器会使用默认值
        */
        let zeroByTwo = SizeV2(height: 2.0)
        print(zeroByTwo.width, zeroByTwo.height)
        // 打印 "0.0 2.0"

        let zeroByZero = SizeV2()
        print(zeroByZero.width, zeroByZero.height)
        // 打印 "0.0 0.0"
        
        printEndLine(title)
    }
    
    /// 4 值类型的构造器代理
    func initializerDelegationForValueTypes() {
        let title = "4 值类型的构造器代理";
        printStartLine(title)
        
        // 构造器 init()，在功能上跟没有自定义构造器时自动获得的默认构造器是一样的，origin 和 size 属性都使用定义时的默认值
        let basicRect = RectV2()
        // basicRect 的 origin 是 (0.0, 0.0)，size 是 (0.0, 0.0)
        print(basicRect)

        // 构造器 init(origin:size:)，在功能上跟结构体在没有自定义构造器时获得的逐一成员构造器是一样的，将 origin 和 size 的实参值赋给对应的存储型属性
        let originRect = RectV2(origin: PointV3(x: 2.0, y: 2.0),
            size: SizeV2(width: 5.0, height: 5.0))
        // originRect 的 origin 是 (2.0, 2.0)，size 是 (5.0, 5.0)
        print(originRect)

        // 构造器 init(center:size:) 先通过 center 和 size 的值计算出 origin 的坐标，然后再调用（或者说代理给）init(origin:size:) 构造器来将新的 origin 和 size 值赋值到对应的属性中
        let centerRect = RectV2(center: PointV3(x: 4.0, y: 4.0),
            size: SizeV2(width: 3.0, height: 3.0))
        // centerRect 的 origin 是 (2.5, 2.5)，size 是 (3.0, 3.0)
        print(centerRect)
        
        printEndLine(title)
    }
    
    /// 5.5 构造器的继承和重写
    func initializerInheritanceAndOverriding() {
        let title = "5.5 构造器的继承和重写";
        printStartLine(title)
        
        // 使用默认构造器创建 numberOfWheels 为 0 的 Vehicle 实例
        let vehicle = VehicleV2()
        print("Vehicle: \(vehicle.description)")
        // Vehicle: 0 wheel(s)
        
        // 创建一个 Bicycle 实例，调用继承的 description 计算型属性去查看属性 numberOfWheels 是否有改变
        let bicycle = BicycleV2()
        print("Bicycle: \(bicycle.description)")
        // 打印“Bicycle: 2 wheel(s)”
        
        // Hoverboard 的实例用 Vehicle 构造器里默认的轮子数量。
        let hoverboard = Hoverboard(color: "silver")
        print("Hoverboard: \(hoverboard.description)")
        // Hoverboard: 0 wheel(s) in a beautiful silver
        
        printEndLine(title)
    }
    
    /// 5.7 指定构造器和便利构造器实践
    func designatedAndConvenienceInitializersInAction() {
        let title = "5.7 指定构造器和便利构造器实践";
        printStartLine(title)
        
        // 使用一个特定的名字来创建新的 Food 实例
        let namedMeat = Food(name: "Bacon")
        // namedMeat 的名字是 "Bacon"
        print(namedMeat.name)

        let mysteryMeat = Food()
        // mysteryMeat 的名字是 [Unnamed]
        print(mysteryMeat.name)
        
        let oneMysteryItem = RecipeIngredient()
        let oneBacon = RecipeIngredient(name: "Bacon")
        let sixEggs = RecipeIngredient(name: "Eggs", quantity: 6)
        print(oneMysteryItem.name, oneMysteryItem.quantity)
        print(oneBacon.name, oneBacon.quantity)
        print(sixEggs.name, sixEggs.quantity)
        
        // 使用三个继承来的构造器来创建 ShoppingListItem 的新实例，数组的类型也能被自动推导为 [ShoppingListItem]
        let breakfastList = [
            ShoppingListItemV2(),
            ShoppingListItemV2(name: "Bacon"),
            ShoppingListItemV2(name: "Eggs", quantity: 6),
        ]
        breakfastList[0].name = "Orange juice"
        breakfastList[0].purchased = true
        for item in breakfastList {
            print(item.description)
        }
        // 1 x Orange juice ✔
        // 1 x Bacon ✘
        // 6 x Eggs ✘
        
        printEndLine(title)
    }
    
    /// 6 可失败构造器
    func failableInitializers() {
        let title = "6 可失败构造器";
        printStartLine(title)
        
        // 实现针对数字类型转换的可失败构造器
        let wholeNumber: Double = 12345.0 // 12345.1
        let pi = 3.14159
         
         // 确保数字类型之间的转换能保持精确的值，使用这个 init(exactly:) 构造器
        if Int(exactly: wholeNumber) != nil {
            // maintain value：保持值
            // 12345.0
            print("\(wholeNumber) conversion to int maintains value")
        } else {
            // 12345.1
            print("\(wholeNumber) conversion to int does not maintain value")
        }
        // 打印“12345.0 conversion to Int maintains value of 12345”
         
        // 如果类型转换不能保持值不变，则这个构造器构造失败
        let valueChanged = Int(exactly: pi)
        // valueChanged 是 Int? 类型，不是 Int 类型

        if valueChanged == nil {
            print("\(pi) conversion to int does not maintain value")
        }
        // 打印“3.14159 conversion to Int does not maintain value”
        
        // 通过该可失败构造器来尝试构建一个 Animal 的实例，并检查构造过程是否成功：
        let someCreature = Animal(species: "Giraffe") // Giraffe 长颈鹿
        // someCreature 的类型是 Animal? 而不是 Animal
         
        if let giraffe = someCreature {
            print("An animal was initialized with a species of \(giraffe.species)")
        }
        // 打印“An animal was initialized with a species of Giraffe”

        // 给该可失败构造器传入一个空字符串到形参 species，则会导致构造失败：
        let anonymousCreature = Animal(species: "")
        // anonymousCreature 的类型是 Animal?, 而不是 Animal
         
        if anonymousCreature == nil {
            print("The anonymous creature could not be initialized")
        }
        // 打印“The anonymous creature could not be initialized”
        
        printEndLine(title)
    }
    
    /// 6.1 枚举类型的可失败构造器
    func failableInitializersForEnumerations() {
        let title = "6.1 枚举类型的可失败构造器";
        printStartLine(title)
        
        // 利用可失败构造器在三个枚举成员中选择合适的枚举成员，当形参不能和任何枚举成员相匹配时，则构造失败：
        let fahrenheitUnit = TemperatureUnit(symbol: "F")
        if fahrenheitUnit != nil {
            print("This is a defined temperature unit, so initialization succeeded.")
        }
        // 打印“This is a defined temperature unit, so initialization succeeded.”
         
        let unknownUnit = TemperatureUnit(symbol: "X")
        if unknownUnit == nil {
            print("This is not a defined temperature unit, so initialization failed.")
        }
        // 打印“This is not a defined temperature unit, so initialization failed.”
        
        printEndLine(title)
    }
    
    /// 6.2 带有原始值的枚举类型的可失败构造器
    func failableInitializersForEnumerationsWithRawValues() {
        let title = "6.2 带有原始值的枚举类型的可失败构造器";
        printStartLine(title)
        
        let fahrenheitUnit = TemperatureUnitV2(rawValue: "F")
        if fahrenheitUnit != nil {
            print("This is a defined temperature unit, so initialization succeeded.")
        }
        // 打印“This is a defined temperature unit, so initialization succeeded.”
         
        let unknownUnit = TemperatureUnitV2(rawValue: "X")
        if unknownUnit == nil {
            print("This is not a defined temperature unit, so initialization failed.")
        }
        // 打印“This is not a defined temperature unit, so initialization failed.”
        
        printEndLine(title)
    }
    
    /// 6.3 构造失败的传递
    func propagationOfInitializationFailure() {
        let title = "6.3 构造失败的传递";
        printStartLine(title)
        
        // 传入一个非空字符串 name 以及一个值大于等于 1 的 quantity 来创建一个 CartItem 实例，构造方法成功被执行：
        if let twoSocks = CartItem(name: "sock", quantity: 2) {
            print("Item: \(twoSocks.name), quantity: \(twoSocks.quantity)")
        }
        // 打印“Item: sock, quantity: 2”

        // 以一个值为 0 的 quantity 来创建一个 CartItem 实例，导致 CartItem 构造器失败
        if let zeroShirts = CartItem(name: "shirt", quantity: 0) {
            print("Item: \(zeroShirts.name), quantity: \(zeroShirts.quantity)")
        } else {
            print("Unable to initialize zero shirts")
        }
        // 打印“Unable to initialize zero shirts”

        // 传入一个值为空字符串的 name 来创建一个 CartItem 实例，父类 Product 的构造过程失败：
        if let oneUnnamed = CartItem(name: "", quantity: 1) {
            print("Item: \(oneUnnamed.name), quantity: \(oneUnnamed.quantity)")
        } else {
            print("Unable to initialize one unnamed product")
        }
        // 打印“Unable to initialize one unnamed product”
        
        printEndLine(title)
    }
    
    /// 6.4 重写一个可失败构造器
    func overridingAFailableInitializer() {
        let title = "6.4 重写一个可失败构造器";
        printStartLine(title)
        
        // 查看 Document、AutomaticallyNamedDocument、UntitledDocument 定义
        
        printEndLine(title)
    }
    
    /// 7 必要构造器
    func requiredInitializers() {
        let title = "7 必要构造器";
        printStartLine(title)
        
        // 查看 SomeClassV4、SomeSubclass 定义
        
        printEndLine(title)
    }
    
    /// 8 通过闭包或函数设置属性的默认值
    func settingADefaultPropertyValueWithAClosureOrFunction() {
        let title = "8 通过闭包或函数设置属性的默认值";
        printStartLine(title)
        
        // 查看 SomeClassV5 定义
        
        let board = Chessboard()
        print(board.squareIsBlackAt(row: 0, column: 1))
        // 打印“true”
        print(board.squareIsBlackAt(row: 7, column: 7))
        // 打印“false”
        
        printEndLine(title)
    }
}

/// 1.1 构造器
/// 定义一个用来保存华氏温度的结构体
struct Fahrenheit {
    // 拥有一个 Double 类型的存储型属性 temperature
    var temperature: Double
    
    // 定义一个不带形参的构造器 init
    init() {
        // 将存储型属性 temperature 的值初始化为 32.0（华氏温度下水的冰点）
        temperature = 32.0
    }
}

/// 1.2 默认属性值
/// 通过在属性声明时为 temperature 提供默认值来使用更简单的方式定义结构体
struct FahrenheitV2 {
    var temperature = 32.0
}

/// 2.1 形参的构造过程
/// 2.3 不带实参标签的构造器形参
/// 定义一个保存摄氏温度的结构体 Celsius
/// 拥有两个构造器，分别接受不同温标下的温度值来创建新的实例
struct Celsius {
    // 存储摄氏温度
    var temperatureInCelsius: Double
    
    // 构造器拥有一个构造形参，实参标签为 fromFahrenheit，形参命名为 fahrenheit；
    init(fromFahrenheit fahrenheit: Double) {
        // 转换成摄氏温度值，保存在 temperatureInCelsius 中
        temperatureInCelsius = (fahrenheit - 32.0) / 1.8
    }
    
    // 构造器拥有一个构造形参，实参标签为 fromKelvin，形参命名为 kelvin
    init(fromKelvin kelvin: Double) {
        // 转换成摄氏温度值，保存在 temperatureInCelsius 中
        temperatureInCelsius = kelvin - 273.15
    }
    
    // 用已有的摄氏表示的 Double 类型值来创建新的 Celsius 实例
    init(_ celsius: Double) {
        temperatureInCelsius = celsius
    }
}

/// 2.2 形式命名和实参标签
struct Color {
    // 三个常量：red、green 和 blue，存储 0.0 到 1.0 之间的值，表明颜色中红、绿、蓝成分的含量
    let red, green, blue: Double
    
    // 构造器：为红蓝绿提供三个 Double 类型的形参命名
    init(red: Double, green: Double, blue: Double) {
        self.red   = red
        self.green = green
        self.blue  = blue
    }
    
    // 构造器：只包含 white 的 Double 类型的形参
    init(white: Double) {
        // 为三个颜色的属性提供相同的值
        red   = white
        green = white
        blue  = white
    }
}

/// 2.4 可选属性类型
/// 包含一个可选 String 属性 response
class SurveyQuestion {
    var text: String
    // 实例初始化时，自动赋值为 nil，表明“暂时还没有字符“
    var response: String?
    init(text: String) {
        self.text = text
    }
    func ask() {
        print(text)
    }
}

/// 2.5 构造过程中常量属性的赋值
/// 用常量属性替代变量属性 text
class SurveyQuestionV2 {
    // 问题内容 text 在实例被创建之后不会再被修改
    let text: String
    var response: String?
    init(text: String) {
        // 可以在类的构造器中设置常量属性 text 的值
        self.text = text
    }
    func ask() {
        print(text)
    }
}

/// 3 默认构造器
/// 封装购物清单中的某一物品的名字（name）、数量（quantity）和购买状态 purchase state
/// 类中的所有属性都有默认值 且是没有父类的基类
class ShoppingListItem {
    // 可选 String 类型，它将接收一个默认 nil 的默认值
    var name: String?
    var quantity = 1
    var purchased = false
}

/// 3.1 结构体的逐一成员构造器：自动获得一个逐一成员构造器 init(width:height:)
/// 4 值类型的构造器代理：辅助 Rect 结构体定义
struct SizeV2 {
    // 属性默认赋值为 0.0 ，类型被推断出来为 Double
    var width = 0.0, height = 0.0
}

/// 4 值类型的构造器代理
/// 辅助 Rect 结构体定义
struct PointV3 {
    var x = 0.0, y = 0.0
}

/// 4 值类型的构造器代理
/// 代表几何矩形
/// 通过三种方式为 Rect 创建实例
struct RectV2 {
    var origin = PointV3()
    var size = SizeV2()
    
    // 1）使用含有默认值的 origin 和 size 属性来初始化；
    init() {}
    
    // 2）提供指定的 origin 和 size 实例来初始化；
    init(origin: PointV3, size: SizeV2) {
        self.origin = origin
        self.size = size
    }
    
    // 3）提供指定的 center 和 size 来初始化。
    init(center: PointV3, size: SizeV2) {
        let originX = center.x - (size.width / 2)
        let originY = center.y - (size.height / 2)
        self.init(origin: PointV3(x: originX, y: originY), size: size)
    }
    
    // 为某个值类型定义了一个自定义的构造器，将无法访问到默认构造器
    // 如：如果不自定义实现 init() 、init(origin: Point, size: Size)等 原始自带的默认构造器
    // 在新的自定义构造器 init(center: Point, size: Size) 中是无法调用默认构造器的
}

/// 5.5 构造器的继承和重写
/// 一个基类：交通工具，没有提供自定义构造器，会自动获得一个默认构造器
class VehicleV2 {
    // 存储型属性，默认值为 Int 类型的 0
    var numberOfWheels = 0
    // 描述车辆特征 String 类型为 descrpiption 的计算型属性
    var description: String {
        return "\(numberOfWheels) wheel(s)"
    }
}

/// 5.5 构造器的继承和重写
/// 自行车：继承 Vehicle 的子类
class BicycleV2: VehicleV2 {
    // 自定义指定构造器 init()。和父类的指定构造器相匹配，需要带上 override 修饰符
    override init() {
        // 调用父类 Vehicle 的默认构造器，确保在修改属性之前，它所继承的属性 numberOfWheels 能被 Vehicle 类初始化
        super.init()
        // 属性 numberOfWheels 的原值被新值 2 替换。
        numberOfWheels = 2
    }
}

/// 5.5 构造器的继承和重写
/// 悬浮滑板车：Vehicle 的子类，只设置它的 color 属性
class Hoverboard: VehicleV2 {
    var color: String
    // 依赖隐式调用父类的构造器来完成，而不是显示调用 super.init()
    init(color: String) {
        self.color = color
        // super.init() 在这里被隐式调用
    }
    override var description: String {
        return "\(super.description) in a beautiful \(color)"
    }
}

/// 5.7 指定构造器和便利构造器实践
/// 食物：基类，封装食物名字的类
class Food {
    var name: String
    // 类类型没有默认的逐一成员构造器，提供了一个接受单一参数 name 的指定构造器
    // 指定初始化器：确保 Food 实例的所有存储型属性都被初始化
    init(name: String) {
        self.name = name
        // 没有父类，不需要调用 super.init()
    }
    // 没有参数的便利构造器 init()
    convenience init() {
        // 为新食物提供了一个默认的占位名字，通过横向代理到指定构造器 init(name: String) 并给参数 name 赋值为 [Unnamed] 来实现
        self.init(name: "[Unnamed]")
    }
}

/// 5.7 指定构造器和便利构造器实践
/// 配方成分: 食谱中的一项原料
/// 将父类的指定构造器重写为了便利构造器，依然提供了父类的所有指定构造器的实现。因此，RecipeIngredient 会自动继承父类的所有便利构造器。
// 继承版本的 init() 在功能上跟 Food 提供的版本是一样的，只是它会代理到 RecipeIngredient 版本的 init(name: String) 而不是 Food 提供的版本。
class RecipeIngredient: Food {
    var quantity: Int
    // 指定构造器 用来填充 RecipeIngredient 实例的所有属性值
    init(name: String, quantity: Int) {
        self.quantity = quantity
        super.init(name: name)
    }
    // 使用了跟 Food 中指定构造器 init(name: String) 相同的形参
    // 重写了父类的指定构造器 init(name: String)，因此必须在前面使用 override
    override convenience init(name: String) {
        self.init(name: name, quantity: 1)
    }
}

/// 5.7 指定构造器和便利构造器实践
/// 购物单中出现的某一种食谱原料
/// 为引入的所有属性都提供了默认值，并且没有定义任何构造器，将自动继承所有父类中的指定构造器和便利构造器
class ShoppingListItemV2: RecipeIngredient {
    var purchased = false
    // 计算属性
    var description: String {
        var output = "\(quantity) x \(name)"
        output += purchased ? " ✔" : " ✘"
        return output
    }
}

/// 6 可失败构造器
struct Animal {
    // String 类型的常量属性
    let species: String
    // 接受一个名为 species 的 String 类型形参的可失败构造器
    init?(species: String) {
        // 可失败构造器检查传入的species 值是否为一个空字符串。如果为空字符串，则构造失败。否则，species 属性被赋值，构造成功
        if species.isEmpty { return nil }
        self.species = species
    }
}

/// 6.1 枚举类型的可失败构造器
/// 温度单位
enum TemperatureUnit {
    // 包含了三个可能的枚举状态（Kelvin、Celsius 和 Fahrenheit）
    case Kelvin, Celsius, Fahrenheit
    // 根据表示温度单位的 Character 值找出合适的枚举成员的可失败构造器
    init?(symbol: Character) {
        switch symbol {
        case "K":
            self = .Kelvin
        case "C":
            self = .Celsius
        case "F":
            self = .Fahrenheit
        default:
            return nil
        }
    }
}

/// 6.2 带有原始值的枚举类型的可失败构造器
/// 可以用原始值类型的 Character 和进阶的 init?(rawValue:) 构造器重写为：
enum TemperatureUnitV2: Character {
    case Kelvin = "K", Celsius = "C", Fahrenheit = "F"
}

/// 6.3 构造失败的传递
class Product {
    let name: String
    init?(name: String) {
        // 可失败构造器首先检查 name 值，假如 name 值为空字符串，则构造器立即执行失败
        if name.isEmpty { return nil }
        self.name = name
    }
}

/// 6.3 构造失败的传递
/// 建立了一个在线购物车中的物品的模型
class CartItem: Product {
    // 常量存储型属性，并确保该属性的值至少为 1
    let quantity: Int
    init?(name: String, quantity: Int) {
        // 验证接收的 quantity 值是否大于等于 1 。倘若 quantity 值无效，则立即终止整个构造过程，返回失败结果，且不再执行余下代码
        if quantity < 1 { return nil }
        self.quantity = quantity
        super.init(name: name)
    }
}

/// 6.4 重写一个可失败构造器
/// 模拟一个文档并可以用 name 属性来构造，属性的值必须为一个非空字符串或 nil，但不能是一个空字符串
class Document {
    var name: String?
    // 该构造器创建了一个 name 属性的值为 nil 的 document 实例
    init() {}
    // 该构造器创建了一个 name 属性的值为非空字符串的 document 实例
    init?(name: String) {
        self.name = name
        if name.isEmpty { return nil }
    }
}

/// 6.4 重写一个可失败构造器
/// 重写了所有父类引入的指定构造器。确保了无论是使用 init() 构造器，还是使用 init(name:) 构造器，在没有名字或者形参传入空字符串时，生成的实例中的 name 属性总有初始值 "[Untitled]"
class AutomaticallyNamedDocument: Document {
    override init() {
        super.init()
        self.name = "[Untitled]"
    }
    // 用一个不可失败构造器 init(name:) 重写了父类的可失败构造器 init?(name:)
    // 子类用另一种方式处理了空字符串，所以不再需要一个可失败构造器
    override init(name: String) {
        super.init()
        if name.isEmpty {
            self.name = "[Untitled]"
        } else {
            self.name = name
        }
    }
}

/// 6.4 重写一个可失败构造器
/// 可在子类的不可失败构造器中使用强制解包来调用父类的可失败构造器。
class UntitledDocument: Document {
    override init() {
        //  name 属性的值总是 "[Untitled]"，使用了父类的可失败构造器 init?(name:)
        super.init(name: "[Untitled]")!
    }
}

/// 7 必要构造器
/// 在类的构造器前添加 required 修饰符表明所有该类的子类都必须实现该构造器
class SomeClassV4 {
    required init() {
        // 构造器的实现代码
    }
}

/// 7 必要构造器
class SomeSubclass: SomeClassV4 {
    // 子类重写父类的必要构造器时，必须在子类的构造器前也添加 required 修饰符
    required init() {
        // 构造器的实现代码
    }
}

/// 8 通过闭包或函数设置属性的默认值
/// 如何用闭包为属性提供默认值
class SomeClassV5 {
    let someProperty: SomeType = {
        // 在这个闭包中给 someProperty 创建一个默认值
        // someValue 必须和 SomeType 类型相同
        let someValue = SomeType()
        return someValue
    }() // 闭包结尾的花括号后面接了一对空的小括号：告诉 Swift 立即执行此闭包
    // 忽略括号，相当于将闭包本身作为值赋值给了属性，而不是将闭包的返回值赋值给属性
}

/// 8 通过闭包或函数设置属性的默认值
class SomeType {
    
}

/// 8 通过闭包或函数设置属性的默认值
/// 西洋跳棋游戏的棋盘：通过一个闭包来初始化并设置颜色值
struct Chessboard {
    // 一个包含 64 个 Bool 值的数组，值为 true 的元素表示一个黑格，值为 false 的元素表示一个白格
    // 数组中第一个元素代表棋盘上左上角的格子，最后一个元素代表棋盘上右下角的格子
    let boardColors: [Bool] = {
        // 每当一个新的 Chessboard 实例被创建时，赋值闭包则会被执行，boardColors 的默认值会被计算出来并返回
        // 计算棋盘中每个格子对应颜色，并将值保存到一个临时数组 temporaryBoard 中
        var temporaryBoard = [Bool]()
        var isBlack = false
        for i in 1...8 {
            for j in 1...8 {
                temporaryBoard.append(isBlack)
                isBlack = !isBlack
            }
            isBlack = !isBlack
        }
        // 返回的数组会保存到 boardColors 中
        return temporaryBoard
    }()
    // 查询 boardColors 中的值
    func squareIsBlackAt(row: Int, column: Int) -> Bool {
        return boardColors[(row * 8) + column]
    }
}



